package org.manon.json.meta;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.manon.json.custom.CustomSerializer;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class Entity implements HasUniqueId<String> {

	private final Class<?> _entityClass;
	private final String _name;
	private final List<MetaProperty> _properties = new ArrayList<MetaProperty>(8);
	
	private final String _serializer;
	private final String _deserializer;

	private final boolean _filterable;
	
	@SuppressWarnings("rawtypes")
	private Class<? extends CustomSerializer> _customSerializer;
	
	@SuppressWarnings("rawtypes")
	private Class<? extends CustomSerializer> _customDeserializer;
	
	public Entity(Class<?> entityClass,String name,boolean filterable) {
		_entityClass = entityClass;
		_name = name;
		_filterable = filterable;
		_serializer = new StringBuilder().append(_entityClass.getName()).append("__Serializer").toString();
		_deserializer = new StringBuilder().append(_entityClass.getName()).append("__Deserializer").toString();
	}

	/**
	 * @see org.manon.json.meta.HasUniqueId#getId()
	 */
	public String getId() {
		return _name;
	}


	public void addProperties(Collection<MetaProperty> properties) {
		_properties.clear();
		_properties.addAll(properties);
		Collections.sort(_properties, new Comparator<MetaProperty>() {
			public int compare(MetaProperty m1, MetaProperty m2) {
				return m1.compareTo(m2);
			}
		});
	}

	/**
	 * @return the entityClass
	 */
	public Class<?> getEntityClass() {
		return _entityClass;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return _name;
	}
	
	public boolean isFilterable() {
		return _filterable;
	}

	/**
	 * @return the properties
	 */
	public List<MetaProperty> getProperties() {
		return _properties;
	}

	public String getInternalClassNameForSerializer() {
		return _serializer.replace('.', '/');
	}
	
	public String getClassNameForSerializer() {
		return _serializer;
	}
	
	public String getClassNameForDeserializer() {
		return _deserializer;
	}
	
	public String getInternalClassNameForDeserializer() {
		return _deserializer.replace('.', '/');
	}

	public void setCustomSerialiser(@SuppressWarnings("rawtypes") Class<? extends CustomSerializer> customSerializer) {
		_customSerializer = customSerializer;
	}
	
	@SuppressWarnings("rawtypes")
	public Class<? extends CustomSerializer> getCustomSerializer() {
		return _customSerializer;
	}
	
	public boolean hasGeneric() {
		for (MetaProperty property : _properties) {
			if (property instanceof MetaPropertyGeneric) {
				return true;
			}
		}
		return false;
	}

	public List<MetaPropertyGeneric> getGenericProperties() {
		List<MetaPropertyGeneric> generics = new ArrayList<MetaPropertyGeneric>();
		for (MetaProperty property : _properties) {
			if (property instanceof MetaPropertyGeneric) {
				generics.add((MetaPropertyGeneric)property);
			}
		}
		return generics;
	}
	
	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(String string) {
		 return _name.compareTo(string);
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder(512);
		builder.append("Entity {\n\tentityClass=[").append(_entityClass.getName())
				.append("], name=[").append(_name).append("], filterable=[")
				.append(_filterable);
		
		
		builder.append("],\n\tproperties={");
				
		for (MetaProperty property : _properties) {
			builder.append("\n\t\t").append(property);
		}
				
				
		builder.append("\n\t},\n\tserializer=")
				.append(_serializer).append(",\n\tdeserializer=")
				.append(_deserializer).append(",\n\tcustomSerializer=")
				.append(_customSerializer).append(",\n\tcustomDeserializer=")
				.append(_customDeserializer).append("\n}");
		return builder.toString();
	}

}